package logger

import (
	"fmt"
	"io"
	"io/fs"
	"log"
	"os"
	"runtime/debug"
	"strconv"
	"time"
)

var (
	logFile  io.Writer
	logPath  string
	ymStr    string
	ymdStr   string
	filePath string
	logSize  int64
	fileIdx  string
	fileInfo fs.FileInfo
	debugLog *log.Logger
	infoLog  *log.Logger
	warnLog  *log.Logger
	errorLog *log.Logger
	flag     = log.Ldate | log.Ltime
	preStr   = []string{"[DEBUG]", "[INFO]", "[WARN]", "[ERROR]"}
)

func InitLog(logBasePath string) {
	var (
		err      error
		levelArr = []string{"_debug", "_info", "_warn", "_error"}
	)
	logSize = 10 * 1024 * 1024
	logPath = logBasePath
	ymStr = time.Now().Format("200601")
	if _, err = os.Stat(logPath + "/" + ymStr + "/"); os.IsNotExist(err) {
		fmt.Println("日志目录不存在，正在创建......")
		if err = os.Mkdir(logPath+"/"+ymStr+"/", os.ModePerm); err != nil {
			panic("创建日志目录失败：" + err.Error())
			return
		}
		fmt.Println("日志目录创建成功～！")
	}
	ymdStr = time.Now().Format("2006-01-02")
	for idx, level := range levelArr {
		filePath = logPath + "/" + ymStr + "/" + ymdStr + level + ".log"
		// 判断是否存在当前日期的日志文件，不存在则创建
		if fileInfo, err = os.Stat(filePath); err == nil {
			// 存在文件，判断日志文件大小是否超出限制
			if fileInfo.Size() < logSize {
				// 没有超出大小限制，打开当前文件
				logFile, _ = os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
			} else {
				// 超出大小限制，轮询出当前日期、级别的日志文件中最大的索引值
				for i := 0; i < 100; i++ {
					fileIdx = strconv.Itoa(i)
					filePath = logPath + "/" + ymStr + "/" + ymdStr + level + "_" + fileIdx + ".log"
					// 判断当前日期、级别的日志文件是否存在
					if _, err = os.Stat(filePath); err != nil && os.IsNotExist(err) {
						// 不存在，则将当前日志文件重命名
						_ = os.Rename(logPath+"/"+ymStr+"/"+ymdStr+level+".log", filePath)
						// 不存在，则创建一个当前日期、级别、索引的日志文件并打开
						logFile, _ = os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
						break
					}
				}
			}
		} else {
			// 不存在，创建一个当前日期、级别的日志文件并打开
			logFile, _ = os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
		}
		switch idx {
		case 0:
			debugLog = log.New(logFile, preStr[0], flag)
		case 1:
			infoLog = log.New(logFile, preStr[1], flag)
		case 2:
			warnLog = log.New(logFile, preStr[2], flag)
		case 3:
			errorLog = log.New(logFile, preStr[3], flag)
		}
	}
	fmt.Println("日志配置初始化成功～！")
}

func Debug(v ...any) {
	checkLogFileStat("_debug", 0)
	debugLog.Println(v...)
}

func Info(v ...any) {
	checkLogFileStat("_info", 1)
	infoLog.Println(v...)
}

func Warn(v ...any) {
	checkLogFileStat("_warn", 2)
	warnLog.Println(v...)
}

func Error(v ...any) {
	checkLogFileStat("_error", 3)
	errorLog.Println(v...)
	errorLog.Printf("%s", debug.Stack())
}

// checkLogFileStat 检查日志文件否存在，不存在则创建
func checkLogFileStat(level string, idx uint8) {
	var err error
	ymStr = time.Now().Format("200601")
	if _, err = os.Stat(logPath + "/" + ymStr + "/"); os.IsNotExist(err) {
		if err = os.Mkdir(logPath+"/"+ymStr+"/", os.ModePerm); err != nil {
			return
		}
	}
	ymdStr = time.Now().Format("2006-01-02")
	filePath = logPath + "/" + ymStr + "/" + ymdStr + level + ".log"
	// 判断是否存在当前日期的日志文件，不存在则创建
	if fileInfo, err = os.Stat(filePath); err == nil {
		// 存在文件，判断日志文件大小是否超出限制
		if fileInfo.Size() < logSize {
			// 没有超出大小限制，打开当前文件
			logFile, _ = os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
		} else {
			// 超出大小限制，轮询出当前日期、级别的日志文件中最大的索引值
			for i := 0; i < 100; i++ {
				fileIdx = strconv.Itoa(i)
				filePath = logPath + "/" + ymStr + "/" + ymdStr + level + "_" + fileIdx + ".log"
				// 判断当前日期、级别的日志文件是否存在
				if _, err = os.Stat(filePath); err != nil && os.IsNotExist(err) {
					// 不存在，则将当前日志文件重命名
					_ = os.Rename(logPath+"/"+ymStr+"/"+ymdStr+level+".log", filePath)
					// 不存在，则创建一个当前日期、级别、索引的日志文件并打开
					logFile, _ = os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
					break
				}
			}
		}
	} else {
		// 不存在，创建一个当前日期、级别的日志文件并打开
		logFile, _ = os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
	}
	switch idx {
	case 0:
		debugLog = log.New(logFile, preStr[0], flag)
	case 1:
		infoLog = log.New(logFile, preStr[1], flag)
	case 2:
		warnLog = log.New(logFile, preStr[2], flag)
	case 3:
		errorLog = log.New(logFile, preStr[3], flag)
	}
}
